import _thread
import time
import random

MAX_CONTAINERS = 32

def singleton(class_):
    instances = {}
    def getinstance(*args, **kwargs):
        if class_ not in instances:
            instances[class_] = class_(*args, **kwargs)
        return instances[class_]
    return getinstance

class Container:
    def __init__(self, func):
        self.func = func
        self.thread_id = None
        self.running = False
        self.subprocesses = []

    def start(self, *func_args):
        # Accept variable number of arguments
        if not self.running and len(ContainerPool().GetContainers()) < MAX_CONTAINERS:
            self.running = True
            self.thread_id = _thread.start_new_thread(self._run, func_args)
            # Pass as tuple

    def stop(self):
        if self.running:
            self.running = False
            self._stop_subprocesses()
            if self.thread_id is not None:
                #_thread.exit()
                del(self.func) # TODO: Исправить костыль. Работает но неприятно.

    def _run(self, *fargs):
        self.func(*fargs)  # Unpack arguments

    def add_subprocess(self, sub_func, *args):
        sub_thread_id = _thread.start_new_thread(sub_func, args)
        self.subprocesses.append(sub_thread_id)

    def _stop_subprocesses(self):
        for thread_id in self.subprocesses:
            # Here you should implement a way to safely stop subprocesses
            pass
AnonymusContainer = lambda: f"@AnonymusContainer:{''.join([str(random.randint(0,1000)) for _ in range(16)])}"

@singleton
class ContainerPool:
    def __init__(self):
        self.containers = {}

    def GetContainers(self): return self.containers

    def CreateContainer(self, cid, func):
        #if cid == 0xaabbccddee:
        #    cid = f"@AnonymusContainer:{''.join([str(random.randint(0,1000)) for _ in range(16)])}"
        self.containers[cid] = Container(func)

    def RemoveContainer(self, cid):
        container = self.containers.pop(cid, None)
        if container is not None:
            container.stop()

    def GetContainer(self, cid):
        return self.containers.get(cid, None)

def Containerize(cid):
    def wrapper(func):
        def wrapped_func(*args, **kwargs):
            if callable(cid):
                anon = cid()
                pool = ContainerPool()
                pool.CreateContainer(anon, func) 
                container = pool.GetContainer(anon)
                container.start(())
                return func
            else:
                pool = ContainerPool()
                pool.CreateContainer(cid, func) 
                container = pool.GetContainer(cid)
                container.start(())
                return func
        return wrapped_func
    return wrapper
